#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <iostream>

using namespace std;


class ThreadData
{
public:
    ThreadData(string n,pthread_mutex_t* p):name(n),pmtx(p)
    {}
public:
    string name;
    pthread_mutex_t* pmtx;
};
//加上__thread会使得每个线程私有该变量
//__thread int ticket = 100;

//加锁保护:加锁的时候一定要保证加锁力度越小越好
//全局的静态的这样定义  
//pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; //pthread
int ticket = 1000;

void *route(void *arg)
{
    ThreadData* td = (ThreadData*)arg;
    while (1) 
    {
        //加锁、解锁之间的区域被叫做临界区
        //在会串行化的地方要加锁，在这里只有一个线程可以拿到这把锁，并向下执行，其他线程会阻塞在这里
        //锁往后的部分只能串行执行，不能并行执行
        pthread_mutex_lock(td->pmtx); 
        if ( ticket > 0 )  //1.判断的本质也是一种计算，数据读到寄存器，里面放的是当前线程的上下文数据
        {
            usleep(rand()%1000);
            printf("%s sells ticket:%d\n",td->name.c_str() ,ticket);
            //2.也可能出问题
            ticket--;
            //在这里进行解锁
            pthread_mutex_unlock(td->pmtx);
        } 
        else 
        {
            //防止break后一直解不了锁，其他进程进不来
            pthread_mutex_unlock(td->pmtx);
            break;
        }
        //可以让抢票变得更平均，
        usleep(rand()%20000);
    }
    delete td;
} 

#define THREAD_NUM 4

int main()
{
    time_t start = time(nullptr);
    pthread_mutex_t mtx;
    //非全局或静态，可以使用init初始化，使用完用destroy销毁
    pthread_mutex_init(&mtx,nullptr);
    srand((unsigned long)time(nullptr));
    pthread_t t[THREAD_NUM];
    for(int i = 0;i  < THREAD_NUM;i++)
    {
        string name = "thread ";
        name += to_string(i+1);
        ThreadData* td = new ThreadData(name,&mtx);
        pthread_create(t+i, nullptr,route,td); 
    }
    for(int i = 0;i<THREAD_NUM;i++)
    {
        pthread_join(*(t+i),NULL);
    }
    pthread_mutex_destroy(&mtx);
    time_t end = time(nullptr);
    cout << "time :" << int(end-start) << "S" << endl;
}